﻿using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace ThreeDContentPipeline
{
    public class BitmapImage
    {
        public BitmapImage(string file)
        {
            Bitmap bitmap = null;

            Bytes = File.ReadAllBytes(file);
            try
            {
                bitmap = CreateBitmap();

                Width = bitmap.Width;
                Height = bitmap.Height;
            }
            finally
            {
                if (bitmap != null)
                {
                    bitmap.Dispose();
                }
            }
        }

        public int Width
        {
            get;
            private set;
        }

        public int Height
        {
            get;
            private set;
        }

        public byte[] Bytes
        {
            get;
            private set;
        }

        public Bitmap CreateBitmap()
        {
            MemoryStream stream = null;
            Bitmap bitmap = null;

            try
            {
                bitmap = Image.FromStream(stream = new MemoryStream(Bytes)) as Bitmap;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
            return bitmap;
        }

        public byte[] UnZip()
        {
            Bitmap bitmap = null;
            BitmapData bd = null;
            byte[] pixels = new byte[Width * Height * 4];

            try
            {
                bitmap = CreateBitmap();
                bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                for (int y = 0; y != Height; y++)
                {
                    for (int x = 0; x != Width; x++)
                    {
                        int i = y * Width * 4 + x * 4;
                        int j = y * bd.Stride + x * 4;

                        pixels[i++] = Marshal.ReadByte(bd.Scan0, j + 2);
                        pixels[i++] = Marshal.ReadByte(bd.Scan0, j + 1);
                        pixels[i++] = Marshal.ReadByte(bd.Scan0, j + 0);
                        pixels[i++] = Marshal.ReadByte(bd.Scan0, j + 3);
                    }
                }
            }
            finally
            {
                if (bitmap != null)
                {
                    if (bd != null)
                    {
                        bitmap.UnlockBits(bd);
                    }
                    bitmap.Dispose();
                }
            }
            return pixels;
        }

        public void Zip(byte[] pixels)
        {
            Bitmap bitmap = null;
            BitmapData bd = null;

            try
            {
                bitmap = CreateBitmap();

                try
                {
                    bd = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                    for (int y = 0; y != Height; y++)
                    {
                        for (int x = 0; x != Width; x++)
                        {
                            int i = y * bd.Stride + x * 4;
                            int j = y * Width * 4 + x * 4;

                            Marshal.WriteByte(bd.Scan0, i + 2, pixels[j++]);
                            Marshal.WriteByte(bd.Scan0, i + 1, pixels[j++]);
                            Marshal.WriteByte(bd.Scan0, i + 0, pixels[j++]);
                            Marshal.WriteByte(bd.Scan0, i + 3, pixels[j++]);
                        }
                    }
                }
                finally
                {
                    if (bd != null)
                    {
                        bitmap.UnlockBits(bd);
                    }
                }
                SetBitmap(bitmap);
            }
            finally
            {
                if (bitmap != null)
                {
                    bitmap.Dispose();
                }
            }
        }

        public void Convert(ImageFormat format)
        {
            BinaryReader reader = null;
            Bitmap bitmap = null;
            Bitmap bitmap2 = null;

            try
            {
                bitmap = CreateBitmap();
                bitmap2 = new Bitmap(bitmap);
                bitmap2.Save((reader = new BinaryReader(new MemoryStream())).BaseStream, format);
                reader.BaseStream.Position = 0;
                Bytes = reader.ReadBytes((int)reader.BaseStream.Length);
            }
            finally
            {
                if (bitmap != null)
                {
                    bitmap.Dispose();
                }
                if (bitmap2 != null)
                {
                    bitmap2.Dispose();
                }
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }

        public void SetBitmap(Bitmap bitmap)
        {
            BinaryReader reader = null;
            Bitmap bitmap2 = null;

            Width = bitmap.Width;
            Height = bitmap.Height;

            try
            {
                bitmap2 = new Bitmap(bitmap);
                bitmap2.Save((reader = new BinaryReader(new MemoryStream())).BaseStream, ImageFormat.Png);
                reader.BaseStream.Position = 0;
                Bytes = reader.ReadBytes((int)reader.BaseStream.Length);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
                if (bitmap2 != null)
                {
                    bitmap2.Dispose();
                }
            }
        }
    }
}
